home *** CD-ROM | disk | FTP | other *** search
/ Resource Library: Multimedia / Resource Library: Multimedia.iso / maestro / source / timeline / note.c < prev    next >
Encoding:
Text File  |  1993-06-15  |  32.7 KB  |  696 lines

  1. /*
  2.  * Copyright (c) 1990, 1991 Stanford University
  3.  *
  4.  * Permission to use, copy, modify, and distribute this software and 
  5.  * its documentation for any purpose is hereby granted without fee, provided
  6.  * that (i) the above copyright notices and this permission notice appear in
  7.  * all copies of the software and related documentation, and (ii) the name
  8.  * Stanford may not be used in any advertising or publicity relating to
  9.  * the software without the specific, prior written permission of
  10.  * Stanford.
  11.  * 
  12.  * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, 
  13.  * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY 
  14.  * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.  
  15.  *
  16.  * IN NO EVENT SHALL STANFORD BE LIABLE FOR ANY SPECIAL, INCIDENTAL,
  17.  * INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, OR ANY DAMAGES
  18.  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER OR NOT
  19.  * ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF LIABILITY,
  20.  * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
  21.  * SOFTWARE.
  22.  */
  23.  
  24. /* $Header: /Source/Media/collab/TimeLine/RCS/note.c,v 1.11 92/09/24 17:18:28 drapeau Exp $ */
  25. /* $Log:    note.c,v $
  26.  * Revision 1.11  92/09/24  17:18:28  drapeau
  27.  * Added code to AddandDisplayNewNote(): when a new note is added, the
  28.  * "setupTime" field is set to zero milliseconds, indicating that there is
  29.  * no synchronization information for this note yet.
  30.  * In addition to this, it might be prudent to set the current document's
  31.  * syncHints flag to indicate that sync hints are no longer valid.
  32.  * 
  33.  * Revision 1.1  91/10/03  17:38:27  chua
  34.  * In DeleteNote, make adjustments to the XClearArea parameters so that
  35.  * a deleted note is properly erased.
  36.  * 
  37.  * Revision 1.0  91/09/30  16:59:15  chua
  38.  * In ClearAllNotes, the parameter is now tlFrame, instead of an instrument head.
  39.  * 
  40.  * Revision 0.81  91/09/26  18:02:51  chua
  41.  * In CheckNoteSelected, do not deselect note if user has clicked on a previously
  42.  * selected note.
  43.  * 
  44.  * Revision 0.80  91/09/25  13:51:10  chua
  45.  * Changed the instrument field, instInfo, to editInfo.
  46.  * Changed InstrumentInfo to EditInfo.
  47.  * 
  48.  * Revision 0.79  91/09/23  17:12:28  chua
  49.  * Replaced the last parameter in calls to CheckNoteSelected by Error, which
  50.  * indicates that there is no double click.
  51.  * In line 585, change selectedInstrument to noteInstrument.
  52.  * 
  53.  * Revision 0.78  91/09/20  11:40:42  chua
  54.  * 
  55.  * 
  56.  * Revision 0.77  91/09/19  17:28:57  chua
  57.  * Make sure that variables are initialized properly.  Change formatting slightly,
  58.  * so that (if, for, while) statements with only one statement in them will not have
  59.  * braces.
  60.  * 
  61.  * Revision 0.76  91/09/16  15:09:30  chua
  62.  * In line 560, the CheckNoteSelected call was short of one parameter.  This is now
  63.  * remedied.
  64.  * 
  65.  * Revision 0.75  91/09/04  15:10:34  chua
  66.  * Deleted the OverlapErrorMessage function and replace the calls to it by
  67.  * AlertMessage.
  68.  * 
  69.  * Revision 0.74  91/08/26  14:21:52  chua
  70.  * Removed the tlFrame->actualApps variable.
  71.  * 
  72.  * Revision 0.73  91/08/21  16:57:22  chua
  73.  * In CheckNoteSelected, do not deselect note if a double click event has occurred.
  74.  * 
  75.  * Revision 0.72  91/08/19  19:19:08  chua
  76.  * In the InsertNewNote routine, if notes are overlapping, try to move the new note to
  77.  * be adjoining with the note being overlapped.  If this is not possible, an error
  78.  * message is displayed.
  79.  * 
  80.  * In the AddandDisplayNewNote routine, if the document name returned is 'untitled' or
  81.  * the duration field in the selection structure equals -1, do not add the new note,
  82.  * since this means that the filename and/or selection is not specified in the media
  83.  * application.
  84.  * 
  85.  * Revision 0.71  91/08/16  17:01:41  chua
  86.  * Removed some variables which are not used.
  87.  * 
  88.  * Revision 0.70  91/08/08  14:26:51  chua
  89.  * In AddandDisplayNewNote, check that the application is open before proceeding to insert.
  90.  * 
  91.  * Revision 0.69  91/08/02  14:28:53  chua
  92.  * Made changes to DrawMoveNote.  Instead of using the absolute mouse position to draw
  93.  * the new note, we use tlFrame->startX, which would have been set to the correct value
  94.  * in the ScrollTimerNotify procedure.
  95.  * 
  96.  * Revision 0.68  91/08/02  13:26:30  chua
  97.  * Made changes to the moving note code so that it moves correctly under different zoom level
  98.  * and across different canvas mappings.
  99.  * 
  100.  * Revision 0.67  91/08/02  11:45:28  chua
  101.  * Added new comments in the DrawMoveNote function.
  102.  * 
  103.  * Revision 0.66  91/08/02  11:41:47  chua
  104.  * In the AddandDisplayNewNote routine, take out the portion of code that checks if a note
  105.  * previously existed and put the code in a new function, CheckNoteSelected.
  106.  * 
  107.  * This new function will return 0 if the mouse click does not fall on any note, return 1 if
  108.  * it falls on an unselected note, and 2 if it falls on a selected note.
  109.  * 
  110.  * Another new function, DrawMoveNote is also added. This will draw a dragged note at its
  111.  * new position, or back at its old position if there is an overlap error at the new position.
  112.  * 
  113.  * Revision 0.65  91/07/22  15:19:54  chua
  114.  * In the DeleteNote procedure, after clearing a note, redraw any pause markers that have been
  115.  * partially erased.
  116.  * 
  117.  * Revision 0.64  91/07/18  15:07:04  chua
  118.  * In the DeleteNote procedure, after clearing a note, check to see if there are grid lines
  119.  * that need to be redrawn over the cleared area.
  120.  * 
  121.  * Revision 0.63  91/07/17  10:28:46  chua
  122.  * In the DeleteNote procedure, there is no longer any need to check if we need to
  123.  * redraw any anchors when deleting a note, since anchors are no longer drawn.
  124.  * 
  125.  * Revision 0.62  91/07/09  17:00:35  chua
  126.  * Removed a redundant variable, templastX.
  127.  * 
  128.  * Revision 0.61  91/06/25  17:43:04  chua
  129.  * Replaced all occurrences of the constant HalfSecondScale with the value 5 as the constant is not in
  130.  * use anymore.
  131.  * In the appropriate places, scale the positions of notes according to the zoom level, to cater for
  132.  * zooming.
  133.  * 
  134.  * Revision 0.60  91/06/05  16:18:40  chua
  135.  * In the DeleteNote and AddandDisplayNewNote routines, delete the lines which hide the
  136.  * info panel list and reshow it again after it is done updating.  This is because the code
  137.  * for doing this is now in the InitNotesInfo routine.
  138.  * 
  139.  * In the CalculateNoteTime routine, use the duration found in the note structure instead
  140.  * of subtracting the start time from the end time to get the duration.
  141.  * 
  142.  * In the AddandDisplayNewNote routine, set the minimum duration of a new note to half a
  143.  * second, if the value passed by the remote application is less than that.
  144.  * 
  145.  * 
  146.  * Revision 0.59  91/06/04  17:55:06  chua
  147.  * Correct an error in calls to OverlapErrorMessage, where previously there were no 
  148.  * parameters passed.  There should be one parameter, tlFrame.
  149.  * 
  150.  * Revision 0.58  91/06/04  17:37:21  chua
  151.  * Added the copyright comments in the beginning of the file.
  152.  * 
  153.  * Revision 0.57  91/06/04  17:28:08  chua
  154.  * In the AddandDisplayNewNote routine, if the frame is the clipboard, only check if
  155.  * an existing note has been clicked upon.  Do not add a new note if the frame is the
  156.  * clipboard (meaning, if the user tried clicking on the cable in the clipboard window to
  157.  * insert a new note).
  158.  * 
  159.  * Revision 0.56  91/06/04  10:43:20  chua
  160.  * Added a call to UpdateHeader to update the header of the frame whenever
  161.  * there is a change in the status of the change flag.
  162.  * 
  163.  * Revision 0.55  91/06/03  11:11:58  chua
  164.  * Make changes to accomodate multiple documents.  This involves identifying
  165.  * which is the current active window, that is, the one where the last mouse
  166.  * click was done.
  167.  * 
  168.  * Revision 0.54  91/05/30  12:07:52  chua
  169.  * Added an extra parameter in the call to InitNotesInfo.  The second parameter,
  170.  * deselect, indicates if the currently selected note is to be deselected.
  171.  * 
  172.  * Revision 0.53  91/05/29  18:30:59  chua
  173.  * 
  174.  * 
  175.  * Revision 0.52  91/05/29  14:40:27  chua
  176.  * Remove the ClearNoteInfoList function calls as the functionality of this procedure is replaced
  177.  * by the new InitNotesInfo procedure.
  178.  * 
  179.  * Revision 0.51  91/05/28  12:12:44  chua
  180.  * *** empty log message ***
  181.  * 
  182.  * Revision 0.50  91/05/24  16:37:13  chua
  183.  * *** empty log message ***
  184.  * 
  185.  * Revision 0.49  91/05/23  17:39:00  chua
  186.  * *** empty log message ***
  187.  * 
  188.  * Revision 0.48  91/05/22  16:40:22  chua
  189.  * 
  190.  * 
  191.  * Revision 0.47  91/05/22  13:56:24  chua
  192.  * 
  193.  * 
  194.  * Revision 0.46  91/05/22  11:41:03  chua
  195.  * In the DeleteNote and AddandDisplayNewNote routines, include statements setting the XV_SHOW
  196.  * attribute for the notes info panel list such that the panel list is not showing when update
  197.  * is being done and only shown again when update is completed.  New update routines are used,
  198.  * instead of using avlist.  Refer to notesInfo.c for more details.
  199.  * 
  200.  * Revision 0.45  91/05/17  16:56:59  chua
  201.  * *** empty log message ***
  202.  * 
  203.  * Revision 0.44  91/05/15  14:53:42  chua
  204.  * Replaced the part of code which deselects the previously selected note with the DeselectNote function 
  205.  * call.
  206.  * 
  207.  * 
  208.  * Revision 0.43  91/05/15  14:11:15  chua
  209.  * Changes in the function AddandDisplayNewNote.  Since only one note is allowed to be selected for the
  210.  * entire timeline instead of one note per instrument, code is added to check that the previously selected
  211.  * instrument's note is deselected if the user has click on a note.  The deselection is done both on the
  212.  * canvas display as well as on the notes info panel list.
  213.  * 
  214.  * The selectedInstrument pointer is set accordingly to the newly selected instrument (if appropriate, that iis,
  215.  * if the user has clicked on a note and it is not the same previously selected note).
  216.  * 
  217.  * Revision 0.42  1991/04/24  01:01:31  chua
  218.  * The change here is that since the instInfo field (pointer to the instrument info pop-up window)
  219.  * is never NULL now (as the pop-up window is created when the instrument is created), all the
  220.  * statements which test for whether it is not NULL before executing some code is now irrelevant.
  221.  * This means the code inside the if statements are now always executed.
  222.  *
  223.  * Revision 0.41  1991/04/08  21:12:43  chua
  224.  * The new changes have to do with updating the instrument info pop-up windows.
  225.  * DeleteNote function:  If a note is to be deleted, the notes info panel list is first cleared by calling
  226.  *                       the ClearNoteInfoList procedure.  The numnotes counter in the instrument data structure
  227.  *                       is then decremented, and the notes info panel list updated by calling the
  228.  *                       InitNotesInfo procedure (notesInfo.c).
  229.  *                       The above is done assuming the info pop-up window for the instrument has been created.
  230.  *                       If not, the numnotes counter is decremented and none of the above updating of the
  231.  *                       panel list takes place.
  232.  *
  233.  * CalculateNoteTime: This is a new function which will calculate the startMin, startSec, endMin, endSec,
  234.  *                    durationMin, durationSec fields for a Note data structure.
  235.  *
  236.  * AddandDisplayNewNote: A check is first made to see if the info pop-up window for this instrument has
  237.  *                       been created.  If not, the function performs as before.
  238.  *                       If yes, check if the user has click on a note.  Depending on whether the note was
  239.  *                       previously selected or not, it is highlighted or de-highlighted.  The appropriate
  240.  *                       entry in the info panel list is selected as well and the information about the
  241.  *                       selected note loaded into the display fields in the pop-up window.
  242.  *              If a note has not been selected, proceed to insert the note as before.  The only
  243.  *                  difference is that at the end of this function, if the pop-up window has been created,
  244.  *              call this function again but with a xPos that is incremented by 1.  The reason for
  245.  *              doing this is so that the newly inserted note will be detected as being clicked upon
  246.  *              in the second call and will be selected.
  247.  *
  248.  * Revision 0.40  1991/04/01  02:06:21  chua
  249.  * This file contains the procedure for adding or delete a note from an instrument note list.
  250.  * The functions are:
  251.  * OverlapErrorMessage - prints an error message that indicates overlapping notes are not allowed.
  252.  * ClearAllNotes - goes through all the instruments and delete all notes in the note list of each instrument.
  253.  * InsertNewNote - insert a new note into the instrument's note list.
  254.  * DeleteNote - delete a note from an instrument's note list and clear the note from the display.
  255.  * AddandDisplayNewNote - Gets information on a note from the 'remote' application that the selected instrument
  256.  *                        represents, calls InsertNewNote to add the new note in the note list and calls
  257.  *                        DrawNote to display the new note on the canvas.
  258.  * */
  259.  
  260. static char notercsid[] = "$Header: /Source/Media/collab/TimeLine/RCS/note.c,v 1.11 92/09/24 17:18:28 drapeau Exp $";
  261.  
  262. #include "main.h"
  263.  
  264. /*
  265.  * This function clears the note list in all the instruments.  It frees the space allocated to all the notes and resets the notes count variable
  266.  * for each instrument (numnotes) to zero.
  267.  * Called by Load (file.c), UpdateAppsHandler (openApps.c)
  268.  */
  269. void ClearAllNotes(tlFrame)
  270.      TimeLineFramePtr tlFrame;
  271. {
  272.   Instrument *instrument;
  273.   Note *note, *freenote;
  274.   
  275.   instrument = tlFrame->instHead;        
  276.   while (instrument != NULL) 
  277.   {
  278.     note = instrument->firstNote;                    /* Go through the whole note list and free each note */
  279.     while (note != NULL) 
  280.     {
  281.       freenote = note;
  282.       note = note->next;
  283.       free (freenote);
  284.     }      
  285.     instrument->firstNote = NULL;
  286.     instrument->infoNote = NULL;
  287.     instrument->numnotes = 0;
  288.     instrument = instrument->next;
  289.   }
  290. }
  291.  
  292. /*
  293.  * This function will insert a new note into a given instrument's note list.  Notes are stored in ascending order of their starting positions
  294.  * on the timeline, meaning notes that are to be played first will be stored earlier in the list.
  295.  * If a note overlaps with another, try to move it to be adjoining with the overlapping note.  If this is not possible, print an error message.
  296.  * Called by Load (file.c) and AddandDisplayNewNote (note.c)
  297.  */
  298. int InsertNewNote (instrument, newNote, tlFrame)
  299.      Instrument *instrument;
  300.      Note *newNote;
  301.      TimeLineFramePtr tlFrame;
  302. {
  303.   Note *currentNote;
  304.   Note *prevNote;
  305.   int duration;
  306.   
  307.   duration = newNote->ms->duration * PixelsPerSecond / 2;
  308.   if (instrument->firstNote == NULL)                    /* Note list is empty.  Insert at the beginning. */
  309.     instrument->firstNote = newNote;
  310.   else                                    /* Go down the note list to find the appropriate position to insert */
  311.   {
  312.     currentNote = instrument->firstNote;
  313.     prevNote = instrument->firstNote;
  314.     if (currentNote->start > newNote->start) 
  315.     {
  316.       if (newNote->end <= currentNote->start)                /* Insert at the beginning of the note list. */
  317.       {
  318.         newNote->next = currentNote;
  319.         instrument->firstNote = newNote;
  320.     return OK;
  321.       }
  322.       if (currentNote->start - duration >= 0)                /* Move the new note so that it is before the current first note */
  323.       {                                    /* Make sure there is space to make the move */
  324.     newNote->start = currentNote->start - duration;
  325.     newNote->end = currentNote->start;
  326.     CalculateNoteTime (newNote);
  327.     newNote->next = currentNote;
  328.     instrument->firstNote = newNote;
  329.     return OK;
  330.       }
  331.       else                                /* Overlap note error */
  332.       {
  333.     AlertMessage(tlFrame, "There is not enough space to insert the new note.", NULL, NULL);
  334.         return Error;
  335.       }
  336.     }
  337.     else while (currentNote != NULL) 
  338.     {
  339.       if (currentNote->start < newNote->start)
  340.       {
  341.     if (currentNote->end <= newNote->start) 
  342.     {
  343.       if (currentNote->next == NULL)                /* Insert at the end of list */
  344.       {
  345.         currentNote->next = newNote;
  346.         return OK;
  347.       }
  348.       prevNote = currentNote;
  349.       currentNote = currentNote->next;
  350.     }
  351.     else if (currentNote->next == NULL)                /* Insert at the end of list, moving the new note to the end of the current note */
  352.     {
  353.       newNote->start = currentNote->end;
  354.       newNote->end = currentNote->end + duration;
  355.       CalculateNoteTime (newNote);
  356.       InsertNewNote(instrument, newNote, tlFrame);
  357.       return OK;
  358.     }
  359.     else if (currentNote->next->start >= currentNote->end + duration) /* Insert at the end of the current note, after making sure that there is */
  360.     {                                /* enough space between the current note and the next note to make the insert */
  361.       newNote->start = currentNote->end;
  362.       newNote->end = currentNote->end + duration;
  363.       CalculateNoteTime (newNote);
  364.       InsertNewNote(instrument, newNote, tlFrame);
  365.       return OK;
  366.     }
  367.     else                                /* No space to insert the new note */
  368.     {
  369.       AlertMessage(tlFrame, "There is not enough space to insert the new note.", NULL, NULL);
  370.       return Error;
  371.     }
  372.       }
  373.       else if (currentNote->start >= newNote->end)            /* No overlapping problem.  Just insert in the middle of a list */
  374.       {
  375.     prevNote->next = newNote;
  376.     newNote->next = currentNote;
  377.     return OK;
  378.       }
  379.       else if (currentNote->start - duration >= prevNote->end)        /* Insert in the middle of the notes list, before the current note */
  380.       {
  381.     newNote->start = currentNote->start - duration;
  382.     newNote->end = currentNote->start;
  383.     CalculateNoteTime (newNote);
  384.     InsertNewNote(instrument, newNote, tlFrame);
  385.     return OK;
  386.       }
  387.       else                                /* No space to insert the new note */
  388.       {
  389.     AlertMessage(tlFrame, "There is not enough space to insert the new note.", NULL, NULL);
  390.     return Error;
  391.       }
  392.     }
  393.   }
  394.   return OK;
  395. }
  396.  
  397. /*
  398.  * This function will delete a note from an instrument's note list.  It takes as argument a pointer to the instrument node, and the X-coordinate
  399.  * of the mouse click by the user on the canvas.  This xPos is used to compare if the user has indeed click on a note.
  400.  * The function will also update the info pop-up window if a note is to be deleted.
  401.  * 1) Check if the instrument's note list is empty.  If so, return, since this means there is no note to be deleted.
  402.  * 2) Check if the first note is to be deleted.  If so, after deletion, check if the note list is empty (there may be only one note in the note list
  403.  *    initially. 
  404.  * 3) Go through the note list to determine which note is to be deleted.  This is done by comparing xPos to the start and end points of each note.
  405.  *    If xPos falls between this point, then that note is to be deleted, since no overlapping notes are allowed.
  406.  * 4) If such a note (to be deleted) is found (indicated by the currentNote not being NULL), first we note the position of the playback head and
  407.  *    move it away.  This is done just in case the playback head falls on the note.  If it was not moved away, deleting the note will mess up the
  408.  *    drawing of the playback head later, since the color would be different and the XOR mode for the playback head would yield different colors.
  409.  * 5) Now clear the area that the note occupied using XClearArea.  Redraw the segment of the cable that has been erased, and redraw the grid lines 
  410.  *    if necessary.  Also redraw any pause markers that might have been partially erased.
  411.  * 6) Clearing of the note is now done.  The playback head is redrawn in its original position.
  412.  * 7) The change flag is set to 1 and the deleted note is freed from memory.
  413.  * Called by DrawCanvasEventHandler (canvas.c)
  414.  */
  415. void DeleteNote(instrument, xPos, tlFrame)
  416.      Instrument *instrument;
  417.      int xPos;
  418.      TimeLineFramePtr tlFrame;
  419. {
  420.   Note *currentNote, *prevNote;
  421.   Pause *pause;
  422.   int found;
  423.   int templastX;
  424.   int i;
  425.   int width;
  426.   int gridStart;
  427.  
  428.   if (instrument->firstNote == NULL)                    /* Note list is empty, nothing to delete */
  429.     return;    
  430.   currentNote = instrument->firstNote;
  431.   if (xPos >= currentNote->start
  432.       && xPos < currentNote->end)                    /* Check if the first note on the note list is to be deleted */
  433.     instrument->firstNote = currentNote->next;               
  434.   else 
  435.   {
  436.     prevNote = currentNote;
  437.     currentNote = currentNote->next;
  438.     found = 0;
  439.     while (currentNote != NULL && !found) 
  440.     {
  441.       if (xPos >= currentNote->start
  442.       && xPos < currentNote->end)                    /* Found the note to be deleted */
  443.       {
  444.         prevNote->next = currentNote->next;
  445.         found = 1;
  446.       }
  447.       prevNote = currentNote;
  448.       if (!found) currentNote = currentNote->next;
  449.     }
  450.   }
  451.   if (currentNote != NULL) 
  452.   {
  453.     instrument->numnotes--;                        /* Decrement the number of notes counter */
  454.     InitNotesInfo(instrument, 1, tlFrame);
  455.     templastX = tlFrame->lastX;                        /* Remember the playback head position and move it away temporarily */
  456.     DrawPlaybackHead(-1, tlFrame);
  457.     width = (currentNote->end - currentNote->start) / tlFrame->zoomLevel;
  458.     if (width < 2) 
  459.       width = 2;
  460.     XClearArea(tlFrame->dpyDraw, tlFrame->xidDraw, 
  461.            (currentNote->start / tlFrame->zoomLevel) - tlFrame->canvasStart,
  462.            instrument->cableStart - NoteHeight/2, width + 1,
  463.            NoteHeight, FALSE);
  464.     if (tlFrame->gridSpacing > 0)                    /* Check if the grid lines need to be redrawn */
  465.     {
  466.       gridStart = (currentNote->start / tlFrame->zoomLevel) - tlFrame->canvasStart;
  467.       if (gridStart % tlFrame->gridSpacing != 0) 
  468.     gridStart = gridStart - gridStart % tlFrame->gridSpacing + tlFrame->gridSpacing;
  469.       SetLineAttributes(tlFrame, 1);
  470.       XSetForeground(tlFrame->dpyDraw, tlFrame->gc, (long)tlFrame->pixelTable[White]);
  471.       for (i=gridStart; i < (currentNote->end / tlFrame->zoomLevel) - tlFrame->canvasStart; 
  472.        i += tlFrame->gridSpacing)                    /* Draw the grid lines */
  473.     XDrawLine(tlFrame->dpyDraw, tlFrame->xidDraw, tlFrame->gc, i, instrument->cableStart - NoteHeight/2,
  474.           i, instrument->cableStart + NoteHeight/2);
  475.       SetLineAttributes(tlFrame, 2);
  476.     }
  477.     XSetForeground(tlFrame->dpyDraw, tlFrame->gc, (long)tlFrame->pixelTable[Black]); /* Redraw the segment of the cable that was erased */
  478.     XFillRectangle(tlFrame->dpyDraw, tlFrame->xidDraw, tlFrame->gc,
  479.            (currentNote->start / tlFrame->zoomLevel) - tlFrame->canvasStart,
  480.            instrument->cableStart - CableHeight/2, width + 1,
  481.            CableHeight);
  482.     pause = tlFrame->pauseHead;                        /* Redraw any pause markers that have been partially erased */
  483.     while (pause != NULL) 
  484.     {
  485.       XSetForeground(tlFrame->dpyDraw, tlFrame->gc, (long)tlFrame->pixelTable[Red]);
  486.       if (pause->position >= currentNote->start - 1 && pause->position <= currentNote->end) 
  487.     XDrawLine(tlFrame->dpyDraw, tlFrame->xidDraw, tlFrame->gc, 
  488.           (pause->position / tlFrame->zoomLevel) - tlFrame->canvasStart, instrument->cableStart - NoteHeight/2,
  489.           (pause->position / tlFrame->zoomLevel) - tlFrame->canvasStart, 
  490.           instrument->cableStart + NoteHeight/2);
  491.       pause = pause->next;
  492.     }
  493.     DrawPlaybackHead(templastX, tlFrame);                /* Reposition the playback head to original position */
  494.     tlFrame->change = 1;                        /* Set the change flag to 1 */
  495.     UpdateHeader(tlFrame, 1);
  496.     free (currentNote);
  497.   }
  498. }
  499.  
  500. /* 
  501.  * This function will calculate a note's start and end times as well as the duration fields in minutes and seconds.
  502.  * It does this by converting the values in the start and end fields in the note data structure and calculating the appropriate minute and
  503.  * second representations.
  504.  * Called by Load (file.c), AddandDisplayNewNote (note.c)
  505.  */
  506. void CalculateNoteTime (note)
  507.      Note *note;
  508. {
  509.   note->startSec = note->start / PixelsPerSecond;            /* Compute the start and end times, and the duration for the note */
  510.   note->startMin = note->startSec / 60;
  511.   note->startSec = note->startSec - note->startMin * 60;
  512.   note->endSec = note->end / PixelsPerSecond;
  513.   note->endMin = note->endSec / 60;
  514.   note->endSec = note->endSec - note->endMin * 60;
  515.   note->durationSec = (note->ms->duration + 1) / 2;
  516.   note->durationMin = note->durationSec / 60;
  517.   note->durationSec = note->durationSec - note->durationMin * 60;
  518. }
  519.   
  520. /*
  521.  * This function will insert a new note into an instrument's note list.  It takes as argument a pointer to the instrument node, and the X-coordinate
  522.  * of the mouse click by the user on the canvas. The new note will be inserted at this new position.
  523.  * The function will also update the info pop-up window if a note is to be deleted.
  524.  * A check is made to see that the frame is not the clipboard and that the app is currently open before insertion is allowed to proceed.
  525.  * 1) The function checks if the user has clicked on a note.  If so, this note is highlighted (drawn Sunken) and the appropriate entry in the
  526.  *    Info Window Panel List is selected (if the Info Window has been created).  Any previously selected note in the same or another instrument will be
  527.  *    deselected and its info window updated accordingly.  If the user has clicked on a note that was previously selected, this note is deselected and
  528.  *    now no note is selected.  
  529.  * 2) A new media segment is created and its fields are filled by using the network protocol messages to talk to the application concerned.
  530.  *    Check that duration is not zero for the selection obtained from the remote application.  Set the duration to a minimum of a half second if
  531.  *    it is less than that.  
  532.  * 3) If the duration field = -1 or the filename is 'untitled', do not add the new note, since this means there is no valid filename and/or
  533.  *    selection specified in the media application.
  534.  * 4) A new note data structure is then created and initialized appropriately.
  535.  * 5) The InsertNewnote procedure is now called to insert the new note in the instrument's note list.  If there is an error in insertion,
  536.  *    for instance, the note overlaps with an existing one, both the note and media segment data structures are freed and the function returns.
  537.  * 6) If insertion is successful, the number of notes counter is incremented.
  538.  * 7) The function is then called again with the same arguments. Since the new note is now in the notelist, it will be detected and selected by
  539.  *    the first part of the function.  xPos is incremented by 1 to make sure that it is within a note.
  540.  * 8) If the Info Window has not been created, then the note is drawn in the Raised mode.
  541.  *    The DrawNote function is then called to draw the new note on the canvas display.  The playback head is first moved away, the new note drawn,
  542.  *    and then the playback head moved back into position.  This avoids drawing the note over the playback head, which will cause a 'dirty' line mark
  543.  *    when the playback head is drawn in a new position, due to the XOR drawing mode properties of the playback head.
  544.  * Called by DrawCanvasEventHandler (canvas.c), and by itself.
  545.  */
  546. void AddandDisplayNewNote (Instrument*         instrument,
  547.                int            xPos,
  548.                TimeLineFramePtr    tlFrame)
  549. {
  550.   MediaSegment*    ms;
  551.   Note*        newNote;
  552.   int        result;
  553.  
  554.   if (xv_get(tlFrame->TimeLine_window->controls, PANEL_CLIENT_DATA) == 0) /* Clipboard document.  No insertion allowed */
  555.     return;
  556.   if (CheckAppOpen(tlFrame, instrument, 1) == Error)            /* Check if the application is alive */
  557.     return;
  558.   ms = (MediaSegment *) malloc (sizeof(MediaSegment));            /* Create a new media segment */
  559.   result = SenderGetCurrentDocName(instrument->sender, &(ms->documentName)); /* Get the document name from the remote application */
  560.   if (result == -1)
  561.     return;        
  562.   result = SenderGetSelection(instrument->sender,&ms->selection);   /* Get the selection data structure from the remote application */
  563.   if (result == -1)
  564.     return;        
  565.   if (ms->selection->duration != -1 &&                    /* Insert only if there is a valid filename and selection */
  566.       strcmp(ms->documentName, "untitled") != 0) 
  567.   {
  568.     ms->setupTime = 0;                            /* This new note has no synchronization hints yet  */
  569.     ms->duration = ms->selection->duration / 500;
  570.     if (ms->duration == 0 && ms->selection->duration >= 0)        /* Set the minimum duration to half a second even if the selection */
  571.       ms->duration = 1;
  572.     newNote = (Note *) malloc (sizeof(Note));                /* Create a new Note data structure and initialize it */
  573.     newNote->start = xPos;
  574.     newNote->end = xPos + ms->duration * PixelsPerSecond / 2;
  575.     newNote->ms = ms;
  576.     CalculateNoteTime (newNote);
  577.     newNote->next = NULL;
  578.     if (InsertNewNote (instrument, newNote, tlFrame) == Error)        /* Check if inserting the new note into the instrument's note list is  */
  579.     {                                    /* successful. */
  580.       free (ms);                            /* If not, free the ms and newNote data structures and return */
  581.       free (newNote);    
  582.       return;
  583.     }
  584.     instrument->numnotes++;                        /* Increment the count of notes for this instrument */
  585.     InitNotesInfo(instrument, 1, tlFrame);
  586.     tlFrame->change = 1;                        /* Set the change flag to 1 (since there is a change) */
  587.     UpdateHeader(tlFrame, 1);
  588.     CheckNoteSelected(instrument, xPos + 1, tlFrame, Error);
  589.   }
  590. }
  591.  
  592. /*
  593.  * This function checks if xPos falls on a note currently on the TimeLine.  If so, it returns a value of 1 if the note was previously unselected,
  594.  * a value of 2 if the note is already selected.  A value of 0 is returned if xPos does not fall on any note.
  595.  * The parameter doubleClick is used to check if this function is called when a double click has been detected.  If so, do not deselect any previously
  596.  * selected note.
  597.  */
  598. int CheckNoteSelected (instrument, xPos, tlFrame, doubleClick)
  599.      Instrument *instrument;
  600.      int xPos;
  601.      TimeLineFramePtr tlFrame;
  602.      int doubleClick;
  603. {
  604.   Note *currentNote;
  605.   int noteCount = 0;
  606.   int sameNote = 0;
  607.   int found = 0;
  608.   
  609.   currentNote = instrument->firstNote;
  610.   while (currentNote != NULL && !found)
  611.   {
  612.     if (xPos >= currentNote->start
  613.     && xPos < currentNote->end)                    /* Check if the user has clicked on a note */
  614.     {                                    /* If so, highlight the note and select this note entry on the info window panel list */
  615.       if (instrument->infoNote == currentNote &&            /* Check if the user has clicked on a previously selected< note */
  616.       tlFrame->noteInstrument == instrument)
  617.       {
  618.     sameNote = 1;
  619.     found = 2;
  620.     if (doubleClick == OK) 
  621.       found = 1;
  622.       }
  623.       if (doubleClick != OK && found != 2)                /* Deselect note only if not a double click */
  624.     DeselectNote(tlFrame);                        /* Deselect a previously selected note, if any */
  625.       if (sameNote == 0)                        /* Perform the following only if we are selecting a new note, and not deselecting */
  626.       {                                    /* a previously selected one. */
  627.     found = 1;
  628.     instrument->selectedInfoNote = noteCount;            /* Set the selected note variables to this note */
  629.     instrument->infoNote = currentNote;
  630.     SelectNoteInfo (instrument, tlFrame);                /* Select the note */
  631.     xv_set(instrument->editInfo->NoteInfoList,        
  632.            PANEL_LIST_SELECT, instrument->selectedInfoNote, TRUE,
  633.            NULL);
  634.       }
  635.     }
  636.     currentNote = currentNote->next;
  637.     noteCount++;
  638.   }
  639.   return found;  
  640. }
  641.  
  642. /*
  643.  * This function will draw a note at its new position after it has been dragged.  If this new position will cause a note overlap, an error message
  644.  * is printed, and the note will be redrawn at its original position. 
  645.  * The note is deleted at its old position, and a copy of it is created.  This copy is then inserted at the new position, or back at the old position if
  646.  * an error occurs while inserting at the new position.
  647.  */
  648. void DrawMoveNote (instrument, tlFrame, offset)
  649.      Instrument *instrument;
  650.      TimeLineFramePtr tlFrame;
  651.      int offset;
  652. {
  653.   Note *newNote;
  654.   int noteX;
  655.   int start;
  656.   int end;
  657.   int change;
  658.  
  659.   XDrawRectangle(tlFrame->dpyDraw, tlFrame->xidDraw, tlFrame->gcLine, /* Clear the drag note outline */
  660.          (tlFrame->startX  / tlFrame->zoomLevel) - tlFrame->canvasStart - offset, 
  661.          instrument->cableStart - NoteHeight/2, 
  662.          (instrument->infoNote->ms->duration * PixelsPerSecond) / (2 * tlFrame->zoomLevel),
  663.          NoteHeight);
  664.   
  665.   newNote = (Note *) malloc (sizeof(Note));                /* Create a new Note data structure and initialize it */
  666.   newNote->ms = instrument->infoNote->ms;
  667.   start = instrument->infoNote->start;
  668.   end = instrument->infoNote->start + instrument->infoNote->ms->duration * 5;
  669.   newNote->next = NULL;
  670.   change = tlFrame->change;
  671.   DeleteNote(instrument, instrument->infoNote->start, tlFrame);    /* Delete the note at its old position */
  672.   noteX = (tlFrame->startX / tlFrame->zoomLevel) - tlFrame->canvasStart - offset;
  673.   if (tlFrame->gridSpacing > 0)                        /* Snap to grid line if necessary */
  674.     noteX = noteX - noteX % tlFrame->gridSpacing;
  675.   noteX = (noteX + tlFrame->canvasStart) * tlFrame->zoomLevel;
  676.   if (noteX < 0) 
  677.     noteX = 0;
  678.   newNote->start = noteX;
  679.   newNote->end = noteX + newNote->ms->duration * 5;
  680.   CalculateNoteTime (newNote);
  681.   tlFrame->change = 1;                            /* Set the change flag to 1 (since there is a change) */
  682.   if (InsertNewNote (instrument, newNote, tlFrame) == Error)        /* Check if insert of the note at the new position is successful */
  683.   {
  684.     newNote->start = start;
  685.     newNote->end = end;
  686.     CalculateNoteTime (newNote);
  687.     InsertNewNote (instrument, newNote, tlFrame);            /* Insert the note back at the old position */
  688.     tlFrame->change = change;                        /* Set the change flag to whatever its value was before the attempted note move */
  689.   }
  690.   instrument->numnotes++;                        /* Increment the count of notes for this instrument */
  691.   InitNotesInfo(instrument, 1, tlFrame);
  692.   UpdateHeader(tlFrame, tlFrame->change);
  693.   CheckNoteSelected(instrument, newNote->start, tlFrame, Error);    /* The note at its new position will be drawn in this routine */
  694. }
  695.  
  696.